home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / presto / prest1_0.lha / src / callstate.C < prev    next >
C/C++ Source or Header  |  1991-12-11  |  9KB  |  356 lines

  1. /*
  2.  * callstate.c
  3.  *
  4.  * Machine dependent code to remember and restore the callstate
  5.  * so that we can "squirrel" away a user's function call and make it
  6.  * later.
  7.  *
  8.  *
  9.  *    Last modified:        12/21/87
  10.  *    by:            bnb
  11.  *    reason:            make preempt safe by updating sp before
  12.  *                copy args gets done, rather than after.
  13.  *
  14.  *    Chase 8/1/88        added vax code
  15.  */
  16.  
  17.  
  18.  
  19. #define _CALLSTATE_C
  20. #include "presto.h"
  21.  
  22. #ifdef sun
  23. private_t long _fctaddr;
  24. #ifdef mc68020
  25. //
  26. // nargs.c -- Jim and Janet Carson, 12/27/88 @ 1:04am CST
  27. //
  28. //    Implementation of C-callable get-number-arguments function
  29. //    for the motorola 680x0 series microprocessors.
  30. //    I suppose this should be inline...
  31. //
  32. //    This function is dedicated to the poor students of Comp 320,
  33. //    Spring 1989, who had this as a question on their open-book
  34. //    final exam.
  35. //
  36. static int   _ipc;   /* program counter = address of next instruction */
  37. static short _instr; /* instruction at ipc                            */
  38.  
  39. #define     ADDQW1     0x584f
  40. #define     ADDQW2     0x504f
  41. #define     LEA        0x4fef
  42.  
  43. int nargs()
  44. {
  45.     asm("movl     a6, sp@-       "); // 1. Save the frame pointer.
  46.     asm("movl     a6@, a6        "); // 2. Trace back one frame -- not to
  47.                                      //    the routine that called nargs(),
  48.                                      //    but to the routine that called the
  49.                                      //    routine that called nargs().
  50.     asm("movl     a6@(4), __ipc  "); // 3. Get the return address
  51.     asm("movl     sp@+, a6       "); // 4. Restore the frame pointer
  52.  
  53.     _instr = *((short *) _ipc);      // 5. Get the next instruction after the
  54.                                      //    return address.  The next
  55.                                      //    instruction is one of the following:
  56.     if (_instr == ADDQW1)            // a. addql #4.  There was ONE argument.
  57.        return(1);
  58.     else if (_instr == ADDQW2)       // b. addql #8.  There were TWO arguments.
  59.        return(2);
  60.     else if ( _instr  == LEA)        // c. lea sp@(JJ), sp.  (where JJ is the
  61.                                      //    short word following the lea instr.)
  62.                                      //    There were JJ/4 arguments.
  63.        return ((int)(*(((short *)_ipc)+1))/4);
  64.     else                             // d. Something else.  There were NO
  65.        return(0);                    //    arguments.
  66. }
  67. #endif /* mc68020 */
  68. #endif /* sun */
  69. #ifdef vax
  70. //
  71. // Caller's saved AP points to the number of args for caller.
  72. // Could be an inline asm.
  73. //
  74. int
  75. nargs()
  76. {
  77.      asm("movl *8(fp), r0");
  78. }
  79. #endif
  80.  
  81. //
  82. // Callstate set called with:
  83. //    pointer to function to be called later on
  84. //    number of args (longwords) it should get called with
  85. //    a pointer to the base of those args
  86. //
  87. // We store this information away and later shove it on to the call
  88. // stack of the function we want to call.
  89. //
  90.  
  91. Callstate::~Callstate()
  92. {
  93. #ifdef mips
  94. #else
  95.     if (cs_argvd)
  96.         delete cs_argvd;
  97. #endif
  98. }
  99.  
  100.  
  101. //
  102. // Copy the arglist into the callstate.  
  103. //    If there are args,
  104. //        and the # args > size of cs space, then
  105. //                delete the existing dynamic cs space
  106. //                make some new ones
  107. //                record size of new cs space
  108. //                copy args into new dynamic space
  109. //        else, have enough room somewhere.  Copy args
  110. //        into dynamic space (if we have it), else into
  111. //        static area.
  112. //
  113. // For the vax, we need to make sure we have two words at the front
  114. // of the cs_argvd block for the arg count and "this" argument.  See
  115. // comments in Callstate::call below.
  116. //
  117. #ifdef mips
  118.  
  119. void
  120. Callstate::set(PFany f, Objany arg)
  121. {
  122.     cs_func = f;
  123.     cs_arg = arg;
  124. }
  125.  
  126. void
  127. Callstate::call(int *sp, Objany obj)
  128. {
  129.     Objany local;
  130.     
  131.     thisthread->andstate(~TS_VIRGIN);
  132.     if (obj)
  133.         local = ((PFRany)cs_func)(obj, cs_arg);
  134.     else
  135.         local = ((PFRany)cs_func)(cs_arg);
  136.     thisthread->terminate((Objany)local);
  137.     //
  138.     // NOT REACHED!
  139.     //
  140.     sp = sp;
  141. }
  142.  
  143. #else /* !mips */
  144.  
  145. void
  146. Callstate::set(PFany f, int argc, int *argv)
  147. {
  148.     register int *ap;
  149.  
  150.     cs_func = f;
  151.     cs_argc = argc;
  152.  
  153.     if (argc)    {
  154.         if (argc > cs_len)    {
  155.             delete cs_argvd;
  156. #ifdef vax
  157.             cs_argvd = new int [argc+2];
  158.             ap = &cs_argvd[2];
  159. #else
  160.             cs_argvd = new int [argc];
  161.             ap = cs_argvd;
  162. #endif
  163.             cs_len = cs_argc;
  164.         } else {
  165. #ifdef vax
  166.             ap = (cs_argvd) ? &cs_argvd[2] : cs_argvs;
  167. #else
  168.             ap = (cs_argvd) ? cs_argvd : cs_argvs;
  169. #endif
  170.         }
  171.         bcopy((char*)argv, (char*)ap, argc * sizeof(int));
  172.     }
  173. }
  174.  
  175.  
  176. //
  177. // Perform the actual call.
  178. //
  179. //    WARNING (for sequent ns32000 version):
  180. //        if the routine we are calling tries to do an nargs
  181. //        its gonna get the wrong answer (0) since we wont
  182. //        have an constant in the adjspb field after the jsr r0
  183. //            'cest la vie...
  184. //
  185. //
  186. //
  187.  
  188. void
  189. Callstate::call(int *sp, Objany obj)
  190. {
  191.     int local = 0;
  192. #ifdef sun
  193.     int func = (int)cs_func;
  194. #else
  195.     int *func = (int *)cs_func;
  196. #endif /* sun */
  197.     int stackbytes = cs_argc * sizeof(long);
  198.  
  199. #ifdef vax
  200.     //
  201.     // We want to use CALLG to avoid copying the args onto the stack.
  202.     // This is weird...we need a contiguous block of longwords containing
  203.     // the arg count followed by the arguments.  We have to play some games
  204.     // since the arguments may be in the callstate struct itself or they
  205.     // may be in the allocated block pointed to by cs_argvd.  If they are
  206.     // in a cs_argvd block, the block will have two extra words at the top
  207.     // for the arg count and the "this" argument.
  208.     //
  209.  
  210.     register int *ap;        // ptr to arg block for callg
  211.  
  212.         if (cs_argvd)
  213.         ap = cs_argvd;
  214.     else
  215.         ap = &cs_argc;
  216.  
  217.     //
  218.     // Hack to properly handle "this" argument with callg.  Yuck.
  219.     //
  220.     if (obj) {
  221.         ap[0] = ++cs_argc;
  222.         ap[1] = (int)obj;
  223.     } else {
  224.         ap++;
  225.         *ap = cs_argc;        // gag
  226.     }
  227.  
  228.     local = (int)ap;
  229.     thisthread->andstate(~TS_VIRGIN);   // XXX WINDOW?
  230.  
  231.         asm("callg *-4(fp), *-8(fp)");
  232.     asm("movl r0, -4(fp)");
  233. #endif /* vax */
  234.  
  235. #if    (sequent || sun)
  236.     //
  237.     // can just toss the args right onto the stack, and do the
  238.     // call ourselves.  Remember to adjust the sp correctly
  239.     // once the call returns
  240.     //
  241.     if (sp == 0)        {     // figure it out for ourselves
  242. #ifdef    ns32000
  243.         asm("sprd    sp, -4(fp)");
  244. #endif
  245. #ifdef    i386
  246.         asm("movl    %esp, -4(%ebp)");
  247. #endif
  248. #ifdef mc68020
  249.         asm("movl       sp, a6@(-4)");
  250. #endif /* mc68020 */
  251.         sp = (int*)local;
  252.     }
  253.  
  254.     //
  255.     // Copy argv from callstate into stack for callee
  256.     // Can't use bcopy here cuz we would be copying over our actual
  257.     // stack.
  258.     //
  259.     if (cs_argc)    {    
  260.         register int *s = cs_argvd ? (cs_argvd) : (cs_argvs);
  261.         register int *d = (int*)(sp - cs_argc);
  262.         //
  263.         // update where we the sp is before we start
  264.         // writing into the stack.  Save ourselves from async
  265.         // interrupts.
  266.         //
  267.         local = (int)(sp - cs_argc);
  268. #ifdef    ns32000
  269.         asm("lprd        sp, -4(fp)");        // sp = local
  270. #endif
  271. #ifdef    i386
  272.         asm("movl        -4(%ebp), %esp");    // sp = local
  273. #endif
  274. #ifdef mc68020
  275.         asm("movl         a6@(-4), sp");    // sp = local;
  276. #endif /* mc68020 */
  277.         while (d != sp)    
  278.             *d++ = *s++;
  279.     }
  280.  
  281.     if (obj)    {
  282.         // shove hidden first argument "this"
  283.         local = (int)obj;
  284. #ifdef    ns32000
  285.         asm("movd        -4(fp), tos");    // sp-- = local
  286. #endif
  287. #ifdef    i386
  288.         asm("pushl        -4(%ebp)");    // sp-- = local
  289. #endif
  290. #ifdef mc68020
  291.         asm("movl         a6@(-4), sp@-"); // sp-- = local
  292. #endif /* mc68020 */
  293.     }
  294.     
  295.     
  296.     // remember the byte count so we can undo  it when func returns
  297.     if (obj)    
  298.         local = -(stackbytes + sizeof(Objany));    // (-4(fp))
  299.     else
  300.         local = -stackbytes;
  301.         
  302.  
  303.     //
  304.     // Safe to preempt now that stack has been set
  305.     //
  306.     thisthread->andstate(~TS_VIRGIN);
  307.  
  308.     //
  309.     // Call intended function and return anything left over in r0.
  310.     //
  311. #ifdef mc68020
  312.     asm("movl        a6@(-8), __fctaddr " ); // a0 = func
  313.     asm("jsr        __fctaddr@       " ); // call func
  314.     asm("addql         #4, sp           ");  // up sp count
  315.     asm("movl        d0, a6@(-4)        " ); // local = d0
  316. #endif /* mc68020 */
  317. #ifdef    ns32000
  318.     asm("movd        -8(fp), r0");        // r0 = func
  319.     asm("jsr        r0");            // call
  320.     asm("adjspb        -4(fp)");        // up sp count
  321.     asm("movd        r0, -4(fp)");        // local = r0;
  322. #endif
  323. #ifdef    i386
  324.     asm("call        *-8(%ebp)");        // call func
  325.     asm("popl        %ecx");            // up sp count
  326.     asm("movl        %eax, -4(%ebp)");    // local = return value
  327. #endif
  328. #endif /*    sequent     */
  329.     
  330.     thisthread->terminate((Objany)local);
  331.     //
  332.     // NOT REACHED!
  333.     //
  334.  
  335. }
  336. #endif /* mips */
  337.  
  338. void
  339. Callstate::print(ostream& s)
  340. {
  341. #ifdef mips
  342.     s << form("(Callstate)this=0x%x, cs_func=0x%x, cs_arg=0x%x", 
  343.         this, cs_func, cs_arg);
  344. #else        
  345.     s << form("(Callstate)this=0x%x, cs_func=0x%x, cs_argc=0x%x, cs_argvs=0x%x, cs_argvd=0x%x", 
  346.         this, cs_func, cs_argc, cs_argvs, cs_argvd);
  347. #endif        
  348. }
  349.  
  350.  
  351. ostream& operator<<(ostream& s, Callstate& c)
  352. {
  353.     c.print(s);
  354.     return s;
  355. }
  356.